﻿//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------

using GameFramework;
using GameFramework.Event;
using GameFramework.Resource;
using System.Collections.Generic;
using UnityEngine;
using UnityGameFramework.Runtime;
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;

namespace StarForce
{
    public class ProcedurePreload : ProcedureBase
    {
        public static readonly string[] DataTableNames = new string[]
        {
            "Aircraft",
            "Armor",
            "Asteroid",
            "Entity",
            "Music",
            "Scene",
            "Sound",
            "Thruster",
            "UIForm",
            "UISound",
            "Weapon",
        };

        private Dictionary<string, bool> m_LoadedFlag = new Dictionary<string, bool>();

        public override bool UseNativeDialog
        {
            get
            {
                return true;
            }
        }

        protected override void OnEnter(ProcedureOwner procedureOwner)
        {
            base.OnEnter(procedureOwner);

            LoadConfigEvent.Success += OnLoadConfigSuccess;
            LoadConfigEvent.Failure += OnLoadConfigFailure;

            LoadDataTableEvent.Success += OnLoadDataTableSuccess;
            LoadDataTableEvent.Failure += OnLoadDataTableFailure;

            LoadDictionaryEvent.Success += OnLoadDictionarySuccess;
            LoadDictionaryEvent.Failure += OnLoadDictionaryFailure;

            m_LoadedFlag.Clear();

            PreloadResources();
        }

        protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
        {
            LoadConfigEvent.Success -= OnLoadConfigSuccess;
            LoadConfigEvent.Failure -= OnLoadConfigFailure;

            LoadDataTableEvent.Success -= OnLoadDataTableSuccess;
            LoadDataTableEvent.Failure -= OnLoadDataTableFailure;

            LoadDictionaryEvent.Success -= OnLoadDictionarySuccess;
            LoadDictionaryEvent.Failure -= OnLoadDictionaryFailure;

            base.OnLeave(procedureOwner, isShutdown);
        }

        protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);

            foreach (KeyValuePair<string, bool> loadedFlag in m_LoadedFlag)
            {
                if (!loadedFlag.Value)
                {
                    return;
                }
            }

            procedureOwner.SetData<VarInt32>("NextSceneId", GameEntry.Config.GetInt("Scene.Menu"));
            ChangeState<ProcedureChangeScene>(procedureOwner);
        }

        private void PreloadResources()
        {
            // Preload configs
            LoadConfig("DefaultConfig");

            // Preload data tables
            foreach (string dataTableName in DataTableNames)
            {
                LoadDataTable(dataTableName);
            }

            // Preload dictionaries
            LoadDictionary("Default");

            // Preload fonts
            LoadFont("MainFont");
        }

        private void LoadConfig(string configName)
        {
            string configAssetName = AssetUtility.GetConfigAsset(configName, false);
            m_LoadedFlag.Add(configAssetName, false);
            GameEntry.Config.ReadData(configAssetName, this);
        }

        private void LoadDataTable(string dataTableName)
        {
            string dataTableAssetName = AssetUtility.GetDataTableAsset(dataTableName, false);
            m_LoadedFlag.Add(dataTableAssetName, false);
            GameEntry.DataTable.LoadDataTable(dataTableName, dataTableAssetName, this);
        }

        private void LoadDictionary(string dictionaryName)
        {
            string dictionaryAssetName = AssetUtility.GetDictionaryAsset(dictionaryName, false);
            m_LoadedFlag.Add(dictionaryAssetName, false);
            GameEntry.Localization.ReadData(dictionaryAssetName, this);
        }

        private void LoadFont(string fontName)
        {
            m_LoadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
            GameEntry.Resource.LoadAsset(AssetUtility.GetFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks(
                (assetName, asset, duration, userData) =>
                {
                    m_LoadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
                    UGuiForm.SetMainFont((Font)asset);
                    Log.Info("Load font '{0}' OK.", fontName);
                },

                (assetName, status, errorMessage, userData) =>
                {
                    Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage);
                }));
        }

        private void OnLoadConfigSuccess(string ConfigAssetName, float Duration, object UserData)
        {
            if (UserData != this)
            {
                return;
            }

            m_LoadedFlag[ConfigAssetName] = true;
            Log.Info("Load config '{0}' OK.", ConfigAssetName);
        }

        private void OnLoadConfigFailure(string ConfigAssetName, string ErrorMessage, object UserData)
        {
            if (UserData != this)
            {
                return;
            }

            Log.Error("Can not load config '{0}' from '{1}' with error message '{2}'.",
                ConfigAssetName, ConfigAssetName, ErrorMessage);
        }

        private void OnLoadDataTableSuccess(string DataTableAssetName, float Duration, object UserData)
        {
            if (UserData != this)
            {
                return;
            }

            m_LoadedFlag[DataTableAssetName] = true;
            Log.Info("Load data table '{0}' OK.", DataTableAssetName);
        }

        private void OnLoadDataTableFailure(string DataTableAssetName, string ErrorMessage, object UserData)
        {
            if (UserData != this)
            {
                return;
            }

            Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.",
                DataTableAssetName, DataTableAssetName, ErrorMessage);
        }

        private void OnLoadDictionarySuccess(string DictionaryAssetName, float Duration, object UserData)
        {
            if (UserData != this)
            {
                return;
            }

            m_LoadedFlag[DictionaryAssetName] = true;
            Log.Info("Load dictionary '{0}' OK.", DictionaryAssetName);
        }

        private void OnLoadDictionaryFailure(string DictionaryAssetName, string ErrorMessage, object UserData)
        {
            if (UserData != this)
            {
                return;
            }

            Log.Error("Can not load dictionary '{0}' from '{1}' with error message '{2}'.",
                DictionaryAssetName, DictionaryAssetName, ErrorMessage);
        }
    }
}
